home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / misc / gs261src.zip / gsht.c < prev    next >
C/C++ Source or Header  |  1993-05-13  |  10KB  |  306 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gsht.c */
  20. /* Halftone operators for Ghostscript library */
  21. #include "math_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gzstate.h"
  25. #include "gzht.h"
  26.  
  27. /* Halftone enumeration structure */
  28. struct gs_screen_enum_s {
  29.     halftone_params ht;        /* constructed here */
  30.     gs_matrix mat;        /* for mapping device x,y to rotated cell */
  31.     int x, y;
  32.     gs_state *pgs;
  33. };
  34.  
  35. /* Exported values */
  36. const uint gs_screen_enum_sizeof = sizeof(gs_screen_enum);
  37.  
  38. /* Forward declarations */
  39. private void set_phase(P1(gs_state *));
  40. private void gx_sort_ht_order(P2(ht_bit *, uint));
  41.  
  42. /* setscreen */
  43. int
  44. gs_setscreen(gs_state *pgs,
  45.   floatp freq, floatp angle, float (*proc)(P2(floatp, floatp)))
  46. {    gs_screen_enum senum;
  47.     gs_point pt;
  48.     int code = gs_screen_init(&senum, pgs, freq, angle);
  49.     if ( code < 0 ) return code;
  50.     while ( (code = gs_screen_currentpoint(&senum, &pt)) == 0 )
  51.         if ( (code = gs_screen_next(&senum, (*proc)(pt.x, pt.y))) < 0 )
  52.             return code;
  53.     if ( code < 0 ) return code;
  54.     pgs->ht_proc = proc;
  55.     set_phase(pgs);
  56.     return 0;
  57. }
  58.  
  59. /* currentscreen */
  60. int
  61. gs_currentscreen(gs_state *pgs,
  62.   float *pfreq, float *pangle, float (**pproc)(P2(floatp, floatp)))
  63. {    halftone_params *pht = pgs->halftone;
  64.     *pfreq = pht->frequency;
  65.     *pangle = pht->angle;
  66.     *pproc = pgs->ht_proc;
  67.     return 0;
  68. }
  69.  
  70. /* sethalftonephase */
  71. int
  72. gs_sethalftonephase(gs_state *pgs, int x, int y)
  73. {    pgs->ht_phase.x = x;
  74.     pgs->ht_phase.y = y;
  75.     set_phase(pgs);
  76.     return 0;
  77. }
  78.  
  79. /* currenthalftonephase */
  80. int
  81. gs_currenthalftonephase(gs_state *pgs, gs_int_point *pphase)
  82. {    *pphase = pgs->ht_phase;
  83.     return 0;
  84. }
  85.  
  86. /* ------ Halftone sampling ------ */
  87.  
  88. /* Set up for halftone sampling */
  89. typedef struct rat_s { int num, denom; } rat_t;
  90. private float adjust_screen_angle(P2(floatp, rat_t *));
  91. /* There may be a fmod function and/or macro defined.... */
  92. #define fmodu(a, b) ((a) - floor((a) / (b)) * (b))
  93. int
  94. gs_screen_init(gs_screen_enum *penum, gs_state *pgs,
  95.   floatp freq, floatp angle)
  96. {    int cell_width, cell_height;
  97.     int tile_width, tile_height;
  98.     int code;
  99.     ht_bit *order;
  100.     rat_t arat;
  101.     float copies;
  102.     if ( freq < 0.1 ) return_error(gs_error_rangecheck);
  103.     /* Convert the frequency to cell width and height */
  104.        {    float cell_size = 72.0 / freq;
  105.         gs_point pcwh;
  106.         gs_matrix imat;
  107.         gs_deviceinitialmatrix(gs_currentdevice(pgs), &imat);
  108.         if ( (code = gs_distance_transform(cell_size, cell_size,
  109.                            &imat, &pcwh)) < 0
  110.             ) return code;
  111.         /* It isn't clear to me whether we should round the */
  112.         /* width and height, truncate them, or do something */
  113.         /* more complicated.  All the problems arise from devices */
  114.         /* whose X and Y resolutions aren't the same: */
  115.         /* the halftone model isn't really designed for this. */
  116.         /* For the moment, truncate and hope for the best. */
  117. #define abs_round(z) (z < 0 ? -(int)(z) : (int)(z))
  118. /*#define abs_round(z) (z < 0 ? -(int)(z - 0.5) : (int)(z + 0.5))*/
  119.         cell_width = abs_round(pcwh.x);
  120.         cell_height = abs_round(pcwh.y);
  121. #undef abs_round
  122.        }
  123.     /* Force a halfway reasonable cell size. */
  124.     if ( cell_width <= 4 ) cell_width = 4;
  125.     if ( cell_height <= 4 ) cell_height = 4;
  126.     angle = adjust_screen_angle(angle, &arat);
  127.     copies = hypot((float)arat.num, (float)arat.denom);
  128.     tile_width = cell_width * copies;
  129.     tile_height = cell_height * copies;
  130.     if ( tile_width > max_ushort / tile_height )
  131.         return_error(gs_error_limitcheck);
  132.     order = (ht_bit *)gs_malloc(tile_width * tile_height, sizeof(ht_bit),
  133.                     "halftone samples");
  134.     if ( order == 0 ) return_error(gs_error_VMerror);
  135.     penum->ht.frequency = freq;
  136.     penum->ht.angle = angle;
  137.     penum->ht.order = order;
  138.     penum->ht.width = tile_width;
  139.     penum->ht.height = tile_height;
  140.     penum->ht.order_size = tile_width * tile_height;
  141.     penum->x = penum->y = 0;
  142.     penum->pgs = pgs;
  143.     /* The transformation matrix must include normalization to the */
  144.     /* interval (-1..1), and rotation by the negative of the angle. */
  145.        {    float xscale = 2.0 / cell_width;
  146.         float yscale = 2.0 / cell_height;
  147.         gs_make_rotation(-angle, &penum->mat);
  148.         penum->mat.xx *= xscale, penum->mat.xy *= xscale;
  149.         penum->mat.yx *= yscale, penum->mat.yy *= yscale;
  150.         penum->mat.tx = -1.0;
  151.         penum->mat.ty = -1.0;
  152.         if_debug8('h', "[h]Screen: %dx%d -> %dx%d [%f %f %f %f]\n",
  153.               cell_width, cell_height, tile_width, tile_height,
  154.               penum->mat.xx, penum->mat.xy,
  155.               penum->mat.yx, penum->mat.yy);
  156.        }
  157.     return 0;
  158. }
  159.  
  160. /* Adjust the angle to one with a rational tangent with */
  161. /* small numerator and denominator. */
  162. private float
  163. adjust_screen_angle(floatp fang, rat_t *prat)
  164. {    float tang = fmodu(fang, 90) * degrees_to_radians;
  165.     int quadrant = (int)fang / 90 % 4;
  166.     const rat_t *ptrat;
  167.     float best_diff, best_ang;
  168.     static const rat_t rattab[9] =
  169.        { {0,1}, {1,3}, {1,2}, {2,3}, {1,1}, {3,2}, {2,1}, {3,1}, {1,0} };
  170.     for ( ptrat = rattab, best_diff = M_PI; ptrat->denom != 0; ptrat++ )
  171.        {    float rang = atan2((double)ptrat->num, (double)ptrat->denom);
  172.         float diff = fabs(tang - rang);
  173.         if ( diff < best_diff )
  174.             best_diff = diff, best_ang = rang, *prat = *ptrat;
  175.        }
  176.     /* If we are in an odd quadrant, swap num and denom. */
  177.     if ( quadrant & 1 )
  178.        {    int temp = prat->num;
  179.         prat->num = prat->denom;
  180.         prat->denom = temp;
  181.        }
  182.     return best_ang * radians_to_degrees + quadrant * 90;
  183. }
  184.  
  185. /* Report current point for sampling */
  186. private int gx_screen_finish(P1(gs_screen_enum *));
  187. int
  188. gs_screen_currentpoint(gs_screen_enum *penum, gs_point *ppt)
  189. {    gs_point pt;
  190.     int code;
  191.     if ( penum->y >= penum->ht.height )    /* all done */
  192.         return gx_screen_finish(penum);
  193.     if ( (code = gs_point_transform(penum->x + 0.5, penum->y + 0.5, &penum->mat, &pt)) < 0 )
  194.         return code;
  195.     while ( pt.x < -1.0 ) pt.x += 2.0;
  196.     while ( pt.x >= 1.0 ) pt.x -= 2.0;
  197.     while ( pt.y < -1.0 ) pt.y += 2.0;
  198.     while ( pt.y >= 1.0 ) pt.y -= 2.0;
  199.     *ppt = pt;
  200.     return 0;
  201. }
  202.  
  203. /* Record next halftone sample */
  204. int
  205. gs_screen_next(gs_screen_enum *penum, floatp value)
  206. {    ushort sample;
  207.     if ( value < -1.0 || value > 1.0 )
  208.       return_error(gs_error_rangecheck);
  209.     /* The following statement was split into two */
  210.     /* to work around a bug in the Siemens C compiler. */
  211.     sample = (ushort)(value * (float)(int)(max_ushort >> 1));
  212.     sample += (max_ushort >> 1);    /* convert from signed to biased */
  213. #ifdef DEBUG
  214. if ( gs_debug['h'] )
  215.    {    gs_point pt;
  216.     gs_screen_currentpoint(penum, &pt);
  217.     dprintf6("[h]sample x=%d y=%d (%f,%f): %f -> %u\n",
  218.          penum->x, penum->y, pt.x, pt.y, value, sample);
  219.    }
  220. #endif
  221.     penum->ht.order[penum->y * penum->ht.width + penum->x].mask = sample;
  222.     if ( ++(penum->x) >= penum->ht.width )
  223.         penum->x = 0, ++(penum->y);
  224.     return 0;
  225. }
  226.  
  227. /* All points have been sampled. */
  228. /* Finish constructing the halftone. */
  229. private int
  230. gx_screen_finish(gs_screen_enum *penum)
  231. {    ht_bit *order = penum->ht.order;
  232.     uint size = penum->ht.order_size;
  233.     uint i;
  234.     int code;
  235.     /* Label each element with its ordinal position. */
  236.     for ( i = 0; i < size; i++ )
  237.         order[i].offset = i;
  238.     /* Sort the samples in increasing order by value. */
  239.     gx_sort_ht_order(order, size);
  240.     /* Set up the actual halftone description. */
  241.     code = gx_ht_construct_order(order, penum->ht.width, penum->ht.height);
  242.     if ( code < 0 ) return code;
  243.     gx_ht_install(penum->pgs, &penum->ht);
  244.     code = gx_remap_color(penum->pgs);
  245.     if ( code < 0 ) return code;
  246.     return 1;            /* all done */
  247. }
  248.  
  249. /* ------ Internal routines ------ */
  250.  
  251. /* Compute the negated halftone phase mod the tile size. */
  252. /* This is the displacement of the tile relative to the device coordinates. */
  253. private void
  254. set_phase(gs_state *pgs)
  255. {    halftone_params *pht = pgs->halftone;
  256.     if ( pht->width == 0 )
  257.         pgs->phase_mod.x = 0;
  258.     else
  259.        {    if ( (pgs->phase_mod.x = -pgs->ht_phase.x % pht->width) < 0 )
  260.             pgs->phase_mod.x += pht->width;
  261.        }
  262.     if ( pht->height == 0 )
  263.         pgs->phase_mod.y = 0;
  264.     else
  265.        {    if ( (pgs->phase_mod.y = -pgs->ht_phase.y % pht->height) < 0 )
  266.             pgs->phase_mod.y += pht->height;
  267.        }
  268. }
  269.  
  270. /* Heapsort (algorithm 5.2.3H, Knuth vol. 2, p. 146), */
  271. /* modified for 0-origin indexing. */
  272. private void
  273. gx_sort_ht_order(ht_bit *recs, uint N)
  274. {    uint l = N >> 1;
  275.     uint r = N - 1;
  276.     uint j;
  277.     ht_bit R;
  278.     if ( N <= 1 ) return;
  279. #define key(m) recs[m].mask
  280. #define K R.mask
  281.     while ( 1 )
  282.        {    if ( l > 0 )
  283.             R = recs[--l];
  284.         else
  285.            {    R = recs[r];
  286.             recs[r] = recs[0];
  287.             if ( --r == 0 )
  288.                {    recs[0] = R;
  289.                 break;
  290.                }
  291.            }
  292.         j = l;
  293.         while ( 1 )
  294.            {    uint i = j;
  295.             j = j + j + 1;
  296.             if ( j < r )
  297.                 if ( key(j) < key(j + 1) ) j++;
  298.             if ( j > r || K >= key(j) )
  299.                {    recs[i] = R;
  300.                 break;    /* to outer loop */
  301.                }
  302.             recs[i] = recs[j];
  303.            }
  304.        }
  305. }
  306.